WebGL 绘制类型与参数化顶点生成
一句话结论:绘制类型决定顶点如何被组装成图元,参数化生成决定顶点数据从哪来,两者配合才能用最少的数据画出想要的形状。
绘制类型与 drawArrays
是什么
绘制类型是 drawArrays 的第一个参数,用来告诉 GPU 如何把顶点序列组装成图元,常用取值有 POINTS、LINES、LINE_STRIP、LINE_LOOP、TRIANGLES、TRIANGLE_STRIP 与 TRIANGLE_FAN。
解决什么问题
它解决同一份顶点数据可以表达不同图形的问题。同样的 4 个点,用 POINTS 画成 4 个散点,用 LINE_LOOP 画成闭合线框,用 TRIANGLE_STRIP 则填充成矩形,无需改变顶点内容。
为什么这样做
GPU 的图元装配阶段是固定硬件,按模式顺序取顶点。把模式作为参数暴露出来,可以用极少的控制信息表达点、线、面等多种图元,避免为每种图形各写一套渲染路径。
怎么用
gl.drawArrays(gl.POINTS, 0, 4); // 4 个独立点
gl.drawArrays(gl.LINES, 0, 4); // 2 条独立线段
gl.drawArrays(gl.LINE_LOOP, 0, 4); // 4 点首尾相连
gl.drawArrays(gl.TRIANGLES, 0, 6); // 2 个独立三角形
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); // 4 点组成条带(2 个三角形)
gl.drawArrays(gl.TRIANGLE_FAN, 0, 4); // 扇形,常用于圆与多边形
| 模式 | 顶点消耗 | 典型用途 |
|---|---|---|
| POINTS | 1 点 / 图元 | 粒子、散点图 |
| LINES | 2 点 / 线段 | 辅助线、线框 |
| LINE_STRIP | n+1 点 / n 段 | 折线、路径 |
| TRIANGLES | 3 点 / 三角形 | 通用网格 |
| TRIANGLE_STRIP | n+2 点 / n 个三角形 | 条带、地形 |
| TRIANGLE_FAN | n+2 点 / n 个三角形 | 圆面、扇形 |
常见坑
- 顶点数不是模式所需整数倍 → 原因:多余顶点被忽略或报错 → 处理:按模式对齐顶点数量
- 用 TRIANGLE_STRIP 却期待独立三角形 → 原因:条带会共享边 → 处理:插入退化三角形或改用 TRIANGLES
- 点太小看不见 → 原因:未设置 gl_PointSize → 处理:在顶点着色器中赋值 gl_PointSize
- 线宽设置无效 → 原因:多数平台只支持 1 像素线宽 → 处理:用三角形模拟粗线
参数化图形顶点生成
是什么
参数化图形顶点生成,是用数学公式按参数(半径、分段数、行列数、宽高)在 CPU 侧计算出顶点位置、法线与 UV,再一次性写入缓冲的过程。
解决什么问题
它解决几何数据的来源问题。手工列出顶点只适用于极简图形,圆形、网格、地形这类规则几何必须用循环生成,参数化还让同一个函数通过调整参数产出不同精度的模型。
为什么这样做
规则几何具有严格的数学结构,用公式生成既准确又紧凑,还能与 LOD 策略配合:远处用低分段,近处用高分段,同一份代码服务不同性能档位,避免为每种精度维护一份模型文件。
怎么用
// 生成圆环顶点(TRIANGLE_STRIP):内外半径 + 分段数
function buildRing(innerR, outerR, segments) {
const data = [];
for (let i = 0; i <= segments; i++) {
const a = (i / segments) * Math.PI * 2;
const cos = Math.cos(a), sin = Math.sin(a);
data.push(innerR * cos, innerR * sin, 0);
data.push(outerR * cos, outerR * sin, 0);
}
return new Float32Array(data); // 共 (segments+1)*2 个顶点
}
// 生成网格顶点:行列数 + 间距
function buildGrid(cols, rows, step) {
const data = [];
for (let r = 0; r <= rows; r++) {
for (let c = 0; c <= cols; c++) {
data.push((c - cols / 2) * step, 0, (r - rows / 2) * step);
}
}
return new Float32Array(data);
}
常见坑
- 圆形段数过少导致边缘明显 → 原因:分段数不足 → 处理:按半径动态决定段数,常用 32 起
- 生成的三角形朝向不一致 → 原因:缠绕顺序混乱 → 处理:统一按逆时针生成并配合面剔除
- 每帧重新生成并上传 → 原因:形状固定却重复计算 → 处理:生成一次后缓存缓冲对象
- 未计算法线与 UV → 原因:只关注位置 → 处理:生成时同步输出法线与纹理坐标
要点总结
- 绘制类型决定组装方式,TRIANGLE_STRIP 与 FAN 能显著减少顶点数
- 顶点数量必须与所选模式对齐,多余顶点会被忽略
- 规则几何用循环按参数生成,分段数可按距离动态调整
- 形状固定的几何生成一次即可,只在参数变化时重建
- 生成时同步输出法线与 UV,避免后续补数据
